package com.mashibing.search.config;

import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.List;

/**
 * @author SNA
 * @date 2025/9/5
 * @Description Elasticsearch高级客户端配置类，用于创建并注册RestHighLevelClient Bean
 **/
@Configuration
public class RestHighLevelClientConfig {

    /*
    * @Value 是 Spring 框架提供的注解，用于将配置文件中的值注入到 Bean 属性中。它可以处理简单的属性注入，也支持复杂的 SpEL（Spring Expression Language）表达式
    * ${elasticsearch.hostAndPorts}：Spring 属性占位符表达式，会从配置文件（如 application.yml 或 bootstrap.yml）中查找名为 elasticsearch.hostAndPorts 的属性值
    * #{...}：这是 SpEL（Spring Expression Language）表达式的语法，允许在注解中使用更复杂的表达式来处理属性值
    * .split(',')：将字符串按逗号分隔成数组
     */
    @Value("#{'${elasticsearch.hostAndPorts}'.split(',')}")
    private List<String> hostAndPorts;

    @Value("${elasticsearch.username}")
    private String username;

    @Value("${elasticsearch.password}")
    private String password;


    @Bean
    public RestHighLevelClient restHighLevelClient() {

        // 创建 HttpHost 数组，其中存放es集群所有节点的地址和端口
        HttpHost[] httpHosts = new HttpHost[hostAndPorts.size()];

        for (int i = 0; i < hostAndPorts.size(); i++) {
            String[] hostAndPort = hostAndPorts.get(i).split(":");
            httpHosts[i] = new HttpHost(hostAndPort[0], Integer.parseInt(hostAndPort[1]));
        }

        // 设置es账号密码认证信息
        /*
        * CredentialsProvider: 这是一个凭证提供者接口，用于提供 访问远程服务所需的认证信息。
        * BasicCredentialsProvider: 这是 CredentialsProvider 的一个基本实现，用于存储和提供凭证。
         */
        CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        /*
        * AuthScope.ANY: 表示凭证适用于任何认证范围（主机、端口、协议等）
        * UsernamePasswordCredentials(username, password): 创建一个包含用户名和密码的凭证对象
        * 这行代码将用户名和密码凭证设置到凭证提供者中，用于后续的认证
         */
        credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));

        // 构建时设置连接信息，基于set设置认证信息
        RestClientBuilder restClientBuilder = RestClient.builder(httpHosts);
        /*
        * setHttpClientConfigCallback: 这是一个回调方法，用于设置 HttpClient 的配置。
        * f -> f.setDefaultCredentialsProvider(credentialsProvider): Lambda 表达式，将之前创建的凭证提供者设置为默认凭证提供者
         */
        restClientBuilder.setHttpClientConfigCallback(f -> f.setDefaultCredentialsProvider(credentialsProvider));

        // 构建连接ES的Client对象
        /*
        * RestHighLevelClient: 这是 Elasticsearch 提供的高级客户端，它在底层客户端（RestClient）的基础上提供了更方便的 API
        * 通过传入配置好的 RestClientBuilder 来创建 RestHighLevelClient 实例
         */
        RestHighLevelClient restHighLevelClient = new RestHighLevelClient(restClientBuilder);
        // 返回
        return restHighLevelClient;

    }
}
